﻿#include "myopenglwidget.h"

unsigned int VAO, VBO, EBO;

float verticesRect[] = { // 画矩形
    0.5f, 0.5f, 0.0f, 0.5f, -0.5f, 0.0f,
    //    -0.5f, 0.5f, 0.0f,
    //    0.5f, -0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f, -0.5f, 0.5f, 0.0f };

unsigned int indices[] = { 0, 1, 3, 1, 2, 3 }; // 需要画的点

// const char *vertexShaderSource = "#version 330 core\n"
//                                 "layout (location = 0) in vec3 aPos;\n"
//                                 "void main()\n"
//                                 "{\n"
//                                 " gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);\n"
//                                 "}\0";

const char *fragmentShaderSource = "#version 330 core\n"
                                   "out vec4 FragColor;\n"
                                   "void main()\n"
                                   "{\n"
                                   " FragColor = vec4(1.0f,0.5f,0.2f,1.0f);\n"
                                   "}\n\0";

MyOpenGLWidget::MyOpenGLWidget( QWidget *parent )
    : QOpenGLWidget( parent ) {}

MyOpenGLWidget::~MyOpenGLWidget() {
    makeCurrent(); // 获取当前状态
    glDeleteBuffers( 1, &VBO );
    glDeleteBuffers( 1, &EBO );
    glDeleteVertexArrays( 1, &VAO ); // 删除顶底和着色器
                                     //    glDeleteShader( shaderProgram );
    doneCurrent();                   // 退出当前状态
}

void MyOpenGLWidget::drawShape( Shape shape ) {
    m_shape = shape;
    update();
}

void MyOpenGLWidget::setWireframe( bool wireframe ) {
    makeCurrent();
    if ( wireframe ) {
        glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    } else {
        glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    }
    update();
    doneCurrent();
}

void MyOpenGLWidget::initializeGL() {
    initializeOpenGLFunctions(); // 本地的指针初始化

    // 创建VAO VBO，并赋予对象ID
    glGenVertexArrays( 1, &VAO );
    glGenBuffers( 1, &VBO );

    // 一次创建多个VAO,VBO
    glBindVertexArray( VAO );
    glBindBuffer( GL_ARRAY_BUFFER, VBO );

    // 为当前绑定到target的缓冲区对象创建一个新的数据存储
    // 如果data不是null，则使用来自此指针的数据初始化数据存储
    //    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
    glBufferData( GL_ARRAY_BUFFER, sizeof( verticesRect ), verticesRect, GL_STATIC_DRAW );

    // 告诉显卡如何解析缓冲区的属性值
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof( float ), (void *) 0 );

    // 开启一个VAO管理的第一个属性值
    glEnableVertexAttribArray( 0 );

    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    //    glBindVertexArray(0);

    /*都被封装了
    // 顶点着色器
    unsigned int vertexShader = glCreateShader( GL_VERTEX_SHADER );
    glShaderSource( vertexShader, 1, &vertexShaderSource, nullptr );
    glCompileShader( vertexShader );

    // 片段着色器
    unsigned int fragmentShader = glCreateShader( GL_FRAGMENT_SHADER );
    glShaderSource( fragmentShader, 1, &fragmentShaderSource, nullptr );
    glCompileShader( fragmentShader );


    // 链接
    shaderProgram = glCreateProgram();
    glAttachShader( shaderProgram, vertexShader );
    glAttachShader( shaderProgram, fragmentShader );
    glLinkProgram( shaderProgram );
    glDeleteShader( vertexShader );
    glDeleteShader( fragmentShader );
    */

    bool success;
    m_shaderProgram.addShaderFromSourceFile( QOpenGLShader::Vertex, ":shaders/shapes.vert" );
    m_shaderProgram.addShaderFromSourceCode( QOpenGLShader::Fragment, fragmentShaderSource );
    success = m_shaderProgram.link();
    if ( !success ) {
        qDebug() << "ERR:" << m_shaderProgram.log();
    }

    // glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);// 设置线条填充
    glGenBuffers( 1, &EBO );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, EBO );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( indices ), indices, GL_STATIC_DRAW );
    //    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );// 这里注释掉，后面的画图的地方可以直接nullptr

    glBindVertexArray( 0 );
}

void MyOpenGLWidget::resizeGL( int w, int h ) {
    Q_UNUSED( w );
    Q_UNUSED( h );
    //    glViewport( 0, 0, w, h );
}

void MyOpenGLWidget::paintGL() {
    glClearColor( 0.2f, 0.3f, 0.3f, 1.0f );
    glClear( GL_COLOR_BUFFER_BIT );
    //    glUseProgram( shaderProgram ); // 使用着色器
    m_shaderProgram.bind();

    glBindVertexArray( VAO ); // 绑定的画图对象

    switch ( m_shape ) {
    case Shape::Rect: {
        glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr ); // 画矩形
        break;
    }
    default:
        break;
    }
}
